#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h> 
#include <time.h>
#include <stdbool.h>

#define WIDTH 60
#define HEIGHT 30
#define INIT_LENGTH 5
// 在函数外部定义颜色方案
#define TITLE_COLOR 11   // 青色
#define MENU_COLOR 14    // 黄色
#define SCORE_COLOR 13   // 紫色
#define GLOW_COLOR 15    // 白色

// 控制台光标操作
void gotoxy(int x, int y) {
    static HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coord = {x, y};
    SetConsoleCursorPosition(hOut, coord);
}

// 设置颜色 
void setColor(int color) {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}

// 蛇结构体
typedef struct {
    int x;
    int y;
} Point;

Point snake[100]; // 蛇身体
int length;       // 蛇长度
int direction;    // 移动方向
int score;        // 当前得分
int bestScore;    // 最高分
Point food;       // 食物位置
int sleeptime = 200; // 移动间隔
int baseScore = 10;   // 基础得分

// 游戏状态
enum GameState { WELCOME, PLAYING, GAMEOVER, HELP };
enum GameState gameState = WELCOME;

// 函数声明
void welcometogame();
void createMap();
void initsnake();
void createfood();
void drawsnake(bool clearTail);
void drawfood();
void snakemove();
void checkCollision();
void keyboardControl();
void updateScore();
void showGameOver();
void saveScore();
void File_out();
void explation();


// 欢迎界面
// 欢迎界面
void welcometogame() {
    system("cls");
    
    // 动态标题参数
    const int titleWidth = 20; // 标题宽度（字符数）
    const int titleX = (WIDTH - titleWidth)/2; // 计算居中位置
    static int glow = 0;
    
    // 动态标题
    setColor(glow ? TITLE_COLOR : GLOW_COLOR);
    gotoxy(titleX, 3);
    printf("▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄");
    gotoxy(titleX, 4);
    printf("█                  █");
    gotoxy(titleX, 5);
    printf("█ ★ 贪吃蛇大作战 ");
    setColor(glow ? GLOW_COLOR : TITLE_COLOR);
    printf("★ █");
    gotoxy(titleX, 6);
    printf("█                  █");
    glow = !glow;

    // 立体菜单参数
    const int menuWidth = 14;  // 菜单宽度（字符数）
    const int baseX = (WIDTH - menuWidth)/2; // 居中计算
    const int baseY = 10;
    
    // 菜单阴影（保持向右偏移2格）
    setColor(8);
    for(int i = 0; i < 3; i++) {
        gotoxy(baseX+2, baseY+i+1);
        printf("██████████");
    }
    
    // 菜单主体
    setColor(MENU_COLOR);
    gotoxy(baseX, baseY);
    printf("╔════════════╗");
    gotoxy(baseX, baseY+1);
    printf("║ 1.开始游戏 ║");
    gotoxy(baseX, baseY+2);
    printf("║ 2.游戏说明 ║"); 
    gotoxy(baseX, baseY+3);
    printf("║ 3.退出游戏 ║");
    gotoxy(baseX, baseY+4);
    printf("╚════════════╝");

    // 动态光标（随菜单居中）
    static int cursorPos = 0;
    setColor(12);
    char cursor = 16; // 右箭头
    gotoxy(baseX-3, baseY+1 + cursorPos);
    printf("%c", cursor);
    if(_kbhit()) {
        int key = _getch();
        switch(key) {
            case 'S': case 's': cursorPos = (cursorPos+1)%3; break;
            case 'W': case 'w': cursorPos = (cursorPos+2)%3; break;
            case '\r': 
                switch(cursorPos) {
                    case 0: gameState = PLAYING; return;
                    case 1: explation(); return;
                    case 2: exit(0);
                }
        }
    }

    // 分数显示（上移2行）
    setColor(SCORE_COLOR);
    gotoxy((WIDTH-20)/2, HEIGHT-6);  // 原HEIGHT-4改为HEIGHT-6
    printf("★ 当前记录：%d ★", bestScore);
    
    // 粒子效果（保持原位置）
    static int particles[5][2] = {{0}};
    for(int i = 0; i < 5; i++) {
        if(particles[i][0] == 0) {
            particles[i][0] = rand()%(WIDTH-10)+5;
            particles[i][1] = HEIGHT-2;
        }
        setColor(rand()%15+1);
        gotoxy(particles[i][0], particles[i][1]);
        printf("·");
        if(--particles[i][1] < 3) particles[i][0] = 0;
    }
    
    Sleep(100);
}

// 创建地图（只在初始化时调用一次）
void createMap() {
    setColor(9);
    for (int i = 0; i < HEIGHT; i++) {
        for (int j = 0; j < WIDTH; j++) {
            if (i == 0 || i == HEIGHT - 1 || j == 0 || j == WIDTH - 1) {
                gotoxy(j, i);
                printf("■");
            }
        }
    }
}

// 初始化蛇
void initsnake() {
    length = INIT_LENGTH;
    direction = 'D'; // 初始向右移动
    for (int i = 0; i < length; i++) {
        snake[i].x = 24 - i * 2;
        snake[i].y = 5;
    }
}

// 生成食物
void createfood() {
    srand(time(NULL));
    bool valid;
    do {
        valid = true;
        food.x = (rand() % ((WIDTH - 4)/2)) * 2 + 2;
        food.y = rand() % (HEIGHT - 4) + 2;
        
        for (int i = 0; i < length; i++) {
            if (snake[i].x == food.x && snake[i].y == food.y) {
                valid = false;
                break;
            }
        }
    } while (!valid);
}

// 绘制蛇（增加清除尾部参数）
void drawsnake(bool clearTail) {
    // 清除旧尾部
    if (clearTail) {
        setColor(0);
        gotoxy(snake[length-1].x, snake[length-1].y);
        printf("  ");
    }

    // 绘制新身体
    setColor(14);
    for (int i = 1; i < length; i++) {
        gotoxy(snake[i].x, snake[i].y);
        printf("★");
    }

    // 绘制新头部（绿色）
    setColor(10);
    gotoxy(snake[0].x, snake[0].y);
    printf("●");
}

// 绘制食物
void drawfood() {
    setColor(12);
    gotoxy(food.x, food.y);
    printf("●");
}

// 移动蛇
void snakemove() {
    // 移动身体
    for (int i = length - 1; i > 0; i--) {
        snake[i] = snake[i - 1];
    }
    // 移动头部
    switch (direction) {
        case 'W': snake[0].y--; break;
        case 'S': snake[0].y++; break;
        case 'A': snake[0].x -= 2; break;
        case 'D': snake[0].x += 2; break;
    }
}

// 碰撞检测
void checkCollision() {
    if (snake[0].x <= 1 || snake[0].x >= WIDTH - 2 ||
        snake[0].y <= 0 || snake[0].y >= HEIGHT - 1) {
        gameState = GAMEOVER;
        return;
    }
    
    for (int i = 1; i < length; i++) {
        if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) {
            gameState = GAMEOVER;
            return;
        }
    }
    
    if (snake[0].x == food.x && snake[0].y == food.y) {
        length++;
        score += baseScore;
        createfood();
        
        // 加速逻辑
        if(sleeptime > 30) {
            sleeptime -= 30;
            baseScore += 2;
        }
        if(sleeptime <= 30) {
            sleeptime = 30;
            baseScore = 10;
        }
    }
}

// 键盘控制
void keyboardControl() {    
    if (_kbhit()) {
        int key = _getch();
        if (key == 0 || key == 0xE0) {
            key = _getch();  
            switch (key) {
                case 59:  // F1加速
                    if(sleeptime > 30) sleeptime -= 30;
                    baseScore += 2;
                    break;
                case 60:  // F2减速
                    if(sleeptime < 350) sleeptime += 30;
                    baseScore = (baseScore > 2) ? baseScore - 2 : 1;
                    break;
            }
            return;
        }
        
        switch (toupper(key)) {
            case 'W': if (direction != 'S') direction = 'W'; break;
            case 'S': if (direction != 'W') direction = 'S'; break;
            case 'A': if (direction != 'D') direction = 'A'; break;
            case 'D': if (direction != 'A') direction = 'D'; break;
            case 27: gameState = GAMEOVER; break;
        }
    }
}

// 更新得分显示
void updateScore() {
    static int lastScore = -1;
    static int lastBest = -1;
    
    if(score != lastScore) {
        setColor(11);
        gotoxy(WIDTH + 4, 5);
        printf("得分: %-6d", score);
        lastScore = score;
    }
    
    if(bestScore != lastBest) {
        setColor(11);
        gotoxy(WIDTH + 4, 6);
        printf("最高分: %-6d", bestScore);
        lastBest = bestScore;
    }
}

// 游戏结束界面
void showGameOver() {
    system("cls");
    setColor(12);
    gotoxy(30,8);
    printf("得分：%d",score);
    gotoxy(30, 9);
    if (score > bestScore) {
        printf("创纪录啦！最高分被你刷新啦，真棒！！！");
        bestScore = score;
        saveScore();
    } else {
        printf("最高分：%d",bestScore);
        gotoxy(30, 10);
        printf("继续努力吧~你离最高分还差:%d",bestScore-score);
    }
    gotoxy(30, 12);
    printf("1：重玩");
    gotoxy(30, 13);
    printf("2：退出游戏");
    gotoxy(30, 15);
    printf("你的选择: ");
    int choice;
    scanf("%d", &choice);
    if (choice == 1) {
        gameState = WELCOME;
        score = 0;
    } else {
        exit(0);
    }
}

// 保存最高分
void saveScore() {
    FILE *fp = fopen("save.txt", "w");
    if (fp) {
        fprintf(fp, "%d", bestScore);
        fclose(fp);
    }
}

// 读取最高分
void File_out() {
    FILE *fp = fopen("save.txt", "r");
    if (fp) {
        fscanf(fp, "%d", &bestScore);
        fclose(fp);
    } else {
        bestScore = 0;
    }
}

// 帮助界面
void explation() {
    system("cls");
    setColor(15);
    gotoxy(25, 5);
    printf("控制:");
    gotoxy(25, 7);
    printf("W - 上");
    gotoxy(25, 8);
    printf("S - 下");
    gotoxy(25, 9);
    printf("A - 左");
    gotoxy(25, 10);
    printf("D - 右");
    gotoxy(25, 12);
    printf("F1 - 加速");
    gotoxy(25, 13);
    printf("F2 - 减速");
    gotoxy(25, 14);
    printf("按 ESC 退出");
    gotoxy(25, 16);
    printf("按任意键返回...");
    _getch();
}

int main() {
    // 隐藏光标
    CONSOLE_CURSOR_INFO cursorInfo = {1, FALSE};
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursorInfo);

    File_out();
    while (1) {
        switch (gameState) {
            case WELCOME:
                welcometogame();
                switch (_getch()) {
                    case '1':
                        gameState = PLAYING;
                        system("cls");
                        createMap();  // 只绘制一次地图
                        initsnake();
                        createfood();
                        drawfood();  // 初始绘制食物
                        break;
                    case '2':
                        explation();
                        break;
                    case '3':
                        exit(0);
                }
                break;
                
            case PLAYING: {
                static Point lastTail;  // 记录上一次的尾部位置
                
                // 清除旧尾部
                setColor(0);
                gotoxy(lastTail.x, lastTail.y);
                printf("  ");
                
                // 记录新尾部
                lastTail = snake[length-1];
                
                // 更新游戏状态
                snakemove();
                checkCollision();
                keyboardControl();
                
                // 局部更新绘制
                drawsnake(false);  // 不清除尾部（已单独处理）
                drawfood();
                updateScore();
                
                Sleep(sleeptime);
                break;
            }
                
            case GAMEOVER:
                showGameOver();
                break;
        }
    }
    return 0;
}